package com.yonyou.crm.sys.role.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yonyou.crm.base.doc.service.BaseDocBizServiceImpl;
import com.yonyou.crm.base.doc.service.BaseDocDetailBizServiceImpl;
import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.enumeration.entity.EnableStateEnum;
import com.yonyou.crm.common.enumeration.service.EnumBizServiceImpl;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.common.field.handler.FieldRelationHandler;
import com.yonyou.crm.common.field.relation.EnumFieldRelation;
import com.yonyou.crm.common.field.relation.FieldRelation;
import com.yonyou.crm.common.field.relation.RefFieldRelation;
import com.yonyou.crm.common.login.context.LoginContextConstant;
import com.yonyou.crm.common.model.util.ModelUtil;
import com.yonyou.crm.common.page.entity.Page;
import com.yonyou.crm.sys.dataright.service.RightServiceImpl;
import com.yonyou.crm.sys.org.service.SysOrgBizServiceImpl;
import com.yonyou.crm.sys.role.entity.RoleDO;
import com.yonyou.crm.sys.role.entity.RoleFuncPerDO;
import com.yonyou.crm.sys.role.entity.RoleVO;
import com.yonyou.crm.sys.tenant.entity.SysTenantVO;
import com.yonyou.crm.sys.tenant.service.SysTenantBizServiceImpl;
import com.yonyou.crm.sys.user.entity.TypeEnum;
import com.yonyou.crm.sys.user.entity.UserVO;
import com.yonyou.crm.sys.user.service.UserBizServiceImpl;
import com.yonyou.iuap.context.InvocationInfoProxy;

@Service
public class RoleBizServiceImpl extends BaseBizServiceImpl<RoleDO> {

	@Autowired
	private SysTenantBizServiceImpl tenantService;
	@Autowired
	private UserBizServiceImpl userService;
	@Autowired
	private SysOrgBizServiceImpl orgService;
	@Autowired
	private EnumBizServiceImpl enumService;
	@Autowired
	private UserBizServiceImpl bizService;
	@Autowired
	private BaseDocDetailBizServiceImpl baseDocDetailBizService;
	@Autowired
	private BaseDocBizServiceImpl docBizService;
	@Autowired
	private RightServiceImpl rightServiceImpl;


	Map<String, Object> paraMap = new HashMap<String, Object>();

	public List<RoleVO> getRoleListByTenantId(Map<String, Object> param) {
		String tenantid = InvocationInfoProxy.getTenantid();
		String userId = InvocationInfoProxy.getParameter(LoginContextConstant.UserId);
		UserVO currentUser = userService.getDetail(Long.parseLong(userId));
		Integer userType = currentUser.getType();
		if(TypeEnum.XTADMIN.getValue() == userType || TypeEnum.JTADMIN.getValue() == userType) {
			//如果系统管理员 或 集团管理员 查看角色 数据为改租户的所有角色 因此 只查看租户条件就ok
		}else {
			//如果公司管理员 查看角色 数据为 集团自定义角色 + 改公司自定义角色 + 预制角色前三种：销售员、销售经理、公司内勤
			//1.获取当前用户集团id
			SysTenantVO tenantVO = tenantService.getSysTenantById(Long.parseLong(tenantid));
			Long groupId = tenantVO.getOrgId();
			//2.获取当前用户公司id
			Long orgId = currentUser.getOrgId();
			Long[] orgIdArr = new Long[]{groupId, orgId, 0L};
			//3.把集团id 和 公司id 组合条件
			param.put("orgIdArr", orgIdArr);
			//4.排除 集团内勤这个 预制的角色，暂定用角色id排除（感觉有些不妥，先这么用吧）
			param.put("noid", 4);

		}
		List<RoleDO> roleList = dao.selectVoList(RoleDO.class,
				"getRoleListByTenantId", param);
		List<RoleVO> roleVOS = ModelUtil.copyModelList(roleList, RoleVO.class);
		transRole(roleVOS);
		return roleVOS;
	}

	public RoleVO getROleDetail(Long id) {
		RoleDO roleDO = super.getVOById(RoleDO.class, id);
		RoleVO roleVO = ModelUtil.copyModel(roleDO, RoleVO.class);
		transRole(Arrays.asList(roleVO));
		return roleVO;
	}

	public List<RoleVO> getUserRole(Long id) {
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("userId", id);
		List<RoleDO> roleList = dao.selectVoList(RoleDO.class, "getUserRole",
				paraMap);
		List<RoleVO> roleVOS = ModelUtil.copyModelList(roleList, RoleVO.class);
		return roleVOS;
	}

	private List<RoleVO> transRole(List<RoleVO> roleList) {

		if (roleList != null && roleList.size() > 0) {

			List<FieldRelation<RoleVO>> relations = new ArrayList<FieldRelation<RoleVO>>();
			relations
					.add(new RefFieldRelation<RoleVO>(RoleVO.class, "orgId",
							new String[] { "orgName" }, orgService,
							"selectFieldsByIds"));
			relations.add(new EnumFieldRelation<RoleVO>(RoleVO.class,
					"isPreseted", "isPresetedName", enumService, "whether"));
			relations.add(new RefFieldRelation<RoleVO>(RoleVO.class, "type",
					new String[] { "typeName" }, baseDocDetailBizService,
					"selectFieldsByIds"));
			new FieldRelationHandler<RoleVO>().handler(roleList, relations);
		}
		return roleList;
	}

	public RoleVO insertRole(RoleVO role) {
		transRole(Arrays.asList(role));
		RoleDO saveDO = super.saveVO(ModelUtil.copyModel(role, RoleDO.class));
		addRoleFuncper(saveDO);//为角色赋分配功能权限
		addRightData(saveDO.getId(),saveDO.getType());//为角色赋分配数据权限
		RoleVO rolevo = ModelUtil.copyModel(saveDO, RoleVO.class);
		return transRole(Arrays.asList(rolevo)).get(0);
	}

	private void addRightData(Long roleId, Integer roleType) {
		Map<String, Object> param = new HashMap<>();
		param.put("roleType", roleType);
		String typeId = dao.selectOne(RoleDO.class, "getRightData",param).toString();
		rightServiceImpl.assign(roleId, typeId);
	}

	private void addRoleFuncper(RoleDO saveDO) {
		Map<String, Object> param = new HashMap<>();
		param.put("roleType", saveDO.getType());
		List<Map<String, Object>> selectList = dao.selectList(RoleDO.class,"getFuncPresetData", param);
		List<Map<String,Object>> listMaps = new ArrayList<Map<String,Object>>();
		for(Map map:selectList){
			Map<String,Object> paramMap = new HashMap<>();
			paramMap.put("roleId", saveDO.getId());
			paramMap.put("funcperId", map.get("funcper_id"));
			paramMap.put("tenantId", saveDO.getTenantId());
			listMaps.add(paramMap);
		}
		dao.saveSql(RoleFuncPerDO.class, "insertRoleFuncPers", listMaps);
	}

	public int getRoleByNameAndOrg(Long id, String name, Long orgId) {
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("id", id);
		paraMap.put("name", name);
		paraMap.put("tenantId", InvocationInfoProxy.getTenantid());
		paraMap.put("orgId", orgId);
		return dao.countAll(RoleDO.class, "getRoleByNameAndOrg", paraMap);
	}

	@Override
	protected void beforeSaveVO(RoleDO vo) {
		if (getRoleByNameAndOrg(null, vo.getName(), vo.getOrgId()) > 0) {
			throw new CrmBusinessException("名称组织唯一，保存失败！");
		}
		super.beforeSaveVO(vo);
	}

	@Override
	protected void beforeUpdateVO(RoleDO vo) {
		if (getRoleByNameAndOrg(vo.getId(), vo.getName(), vo.getOrgId()) > 0) {
			throw new CrmBusinessException("名称组织唯一，保存失败！");
		}
		super.beforeUpdateVO(vo);

	}

	public RoleVO updateRole(RoleVO role) {
		
		RoleDO updateDO = super.updateVO(ModelUtil
				.copyModel(role, RoleDO.class));
		RoleVO roleVO = ModelUtil.copyModel(updateDO, RoleVO.class);
		transRole(Arrays.asList(roleVO));
		return roleVO;
	}

	@Override
	protected void beforeDeleteVO(RoleDO vo) {
		// 删除前校验 关联的用户的角色不许删除
		getUserRoleData(vo.getId());
		super.beforeDeleteVO(vo);
		Byte isPreseted = vo.getIsPreseted();
		if ("".equals(isPreseted) || isPreseted == null) {
			return;
		}
		if (isPreseted.equals(new Byte("1"))) {// 如果是预置数据 不允许删除
			throw new CrmBusinessException("预知角色不允许删除");
		}
	}

	public int deleteRole(Long id) {
		RoleDO roleVO = new RoleDO();
		roleVO.setId(id);
		return super.deleteVO(roleVO);
	}

	/**
	 * 为角色分配用户，向用户角色中间表中添加数据
	 * 
	 * @param roleId
	 * @param userIds
	 * @return
	 */
	public boolean insertUserRole(long roleId, String[] userIds) {

		String[] roleIds = new String[] { String.valueOf(roleId) };
 
		boolean flag = assignUserRole(roleIds, userIds);

		return flag;
	}

	public boolean assignUserRole(String[] roleIds, String[] userIds) {
		String tenantId = InvocationInfoProxy.getTenantid();
		List<Map<String, Object>> paramList = new ArrayList<>();
		for (String roleId : roleIds) {
			for (String userId : userIds) {
				Map<String, Object> map = new HashMap<>();
				map.put("roleId", roleId);
				map.put("userId", userId);
				map.put("tenantId", tenantId);
				paramList.add(map);
			}
		}
		int flag = dao.saveSql(RoleDO.class, "insertUserRole", paramList);
		return flag > 0 ? true : false;

	}

	public Page<UserVO> getPersonals(Page<UserVO> requestPage, Long roleId) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("roleId", roleId);
		List<Map<String, Object>> selectList = dao.selectList(RoleDO.class,
				"getPersonals", paramMap);
		Map param = getParam(selectList, "list");
		if (param != null) {
			param.put("orderBys", "convert(name using gbk) asc");
			param.put("enableState", EnableStateEnum.ENABLE.getValue());
			int userType = bizService.getUserTypeById(Long.valueOf(InvocationInfoProxy.getParameter(LoginContextConstant.UserId)));
			if(TypeEnum.GSADMIN.getValue()==userType){
				param.put("orgId",InvocationInfoProxy.getParameter(LoginContextConstant.OrgId));
			}
			Page<UserVO> page = bizService.getRefPage(requestPage, param);
			return page;
		}
		return new Page<UserVO>();	
	}

	private Map getParam(List<Map<String, Object>> selectList, String type) {
		Map<String, Object> param = new HashMap<>();
		List<Long> list = new ArrayList<>();
		if (selectList != null && selectList.size() > 0) {
			for (Map map : selectList) {
				String userId = map.get("id").toString();
				list.add(Long.valueOf(userId));
			}
			Long[] ids = list.toArray(new Long[0]);
			if ("add".equals(type)) {
				param.put("excludeIds", ids);
			} else {
				param.put("ids", ids);
			}
		} else {
			if ("add".equals(type)) {
				param.put("excludeIds", null);
			} else {
				return null;
			}
		}

		return param;
	}

	public boolean unAssignUser(long roleId, String[] userIds) {
		List<Map<String, Object>> param = new ArrayList<>();
		String tenantId = InvocationInfoProxy.getTenantid();
		for (String userId : userIds) {
			Map<String, Object> map = new HashMap<>();
			map.put("roleId", roleId);
			map.put("userId", userId);
			map.put("tenantId", tenantId);
			param.add(map);
		}
		int flag = dao.deleteSql(RoleDO.class, "deleteUserRole", param);

		return flag > 0 ? true : false;
	}

	public void getUserRoleData(Long id) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("roleId", id);
		List<Map<String, Object>> selectList = dao.selectList(RoleDO.class,
				"getPersonals", paramMap);
		if (selectList != null && selectList.size() > 0) {
			throw new CrmBusinessException("角色已关联用户不允许删除");
		}
	}

	public List<Map<String, Object>> getRoleTypes() {
		String userId = InvocationInfoProxy.getParameter(LoginContextConstant.UserId);
		UserVO userVO = userService.getDetail(Long.parseLong(userId));
		Integer userType = userVO.getType();

		Map<String, Object> param = new HashMap<>();
		String tenantId = InvocationInfoProxy.getTenantid();
		param.put("tenantId", tenantId);
		List<Map<String, Object>> roleTypes = docBizService
				.getDocDetailListByDocname("角色类型");
		if(userType == TypeEnum.GSADMIN.getValue()) {
			//当前用户如果是 公司管理员 角色类型不可见 集团内勤角色类型
			roleTypes.remove(3);
		}

		return roleTypes;
	}

	public List<RoleVO> getRefList(String param) {
		Map<String, Object> paramMap = new HashMap<>();
		String tenantid = InvocationInfoProxy.getTenantid();
		paramMap.put("param", param);
		paramMap.put("tenantId", tenantid);
		String userId = InvocationInfoProxy.getParameter(LoginContextConstant.UserId);
		UserVO currentUser = userService.getDetail(Long.parseLong(userId));
		Integer userType = currentUser.getType();
		if(TypeEnum.XTADMIN.getValue() == userType || TypeEnum.JTADMIN.getValue() == userType) {
			//如果系统管理员 或 集团管理员 查看角色 数据为改租户的所有角色 因此 只查看租户条件就ok
		}else {
			//如果公司管理员 查看角色 数据为 集团自定义角色 + 改公司自定义角色 + 预制角色前三种：销售员、销售经理、公司内勤
			//1.获取当前用户集团id
			SysTenantVO tenantVO = tenantService.getSysTenantById(Long.parseLong(tenantid));
			Long groupId = tenantVO.getOrgId();
			//2.获取当前用户公司id
			Long orgId = currentUser.getOrgId();
			Long[] orgIdArr = new Long[]{groupId, orgId, 0L};
			//3.把集团id 和 公司id 组合条件
			paramMap.put("orgIdArr", orgIdArr);
			//4.排除 集团内勤这个 预制的角色，暂定用角色id排除（感觉有些不妥，先这么用吧）
			paramMap.put("noid", 4);

		}

		List<RoleDO> list = dao.selectVoList(RoleDO.class, "getRefList",
				paramMap);
		List<RoleVO> roleVOS = ModelUtil.copyModelList(list, RoleVO.class);
		return roleVOS;
	}

	/**
	 * 根据角色id翻译角色名称
	 * 
	 * @param ids
	 * @return
	 */
	public Object selectFieldsByIds(Object[] ids) {
		Map<String, Object> para = new HashMap<String, Object>();
		para.put("ids", ids);
		return dao.selectList(RoleDO.class, "selectFieldsByIds", para);
	}

	/**
	 * 按用户删除角色
	 * 
	 * @param roleId
	 * @param userId
	 * @return
	 */
	public boolean userDelRole(String[] userIds) {
		return dao.deleteSql(RoleDO.class, "userDelRole", userIds) > 0;
	}
	
	/**
	 * 角色新增参照列表
	 * @param name
	 * @param orgId
	 * @param roleId
	 * @return
	 */
	public List<UserVO> getAddPersonals(String name, String orgId, Long roleId) {
		Map<String, Object> paramMap = new HashMap<>();
		List<Map<String, Object>> selectList = dao.selectList(RoleDO.class,
				"getAddPersonals", paramMap);
		Map param = getParam(selectList, "add");
		param.put("orderBys", "convert(name using gbk) asc");
		String userId = InvocationInfoProxy.getParameter(LoginContextConstant.UserId);
		int userType = bizService.getUserTypeById(Long.valueOf(userId));
		if(TypeEnum.GSADMIN.getValue()==userType){
			param.put("orgId",orgId);
		}
		param.put("name", name);
		List<UserVO> userVOs = bizService.getRefList(param);
		return userVOs;
	}

	public List<RoleVO> tenantRoles(String tenantId) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("tenantId", tenantId);
		List<RoleDO> selectVoList = dao.selectVoList(RoleDO.class,"tenantRoles", paramMap);
		List<RoleVO> vos = ModelUtil.copyModelList(selectVoList, RoleVO.class);
		return vos;
	}

    public List<String> getUserIdByRoleId(Long roleId) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("tenantId",  InvocationInfoProxy.getTenantid());
		paramMap.put("roleId", roleId);
		List<String> userIds = dao.selectStrList(RoleDO.class, "getUserIdByRoleId", paramMap);
		return userIds;
    }
}
